package com.ruicar.afs.cloud.afscase.approvetask.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.ruicar.afs.cloud.afscase.approvemakelabel.entity.ApproveMakeLabel;
import com.ruicar.afs.cloud.afscase.approvemakelabel.service.ApproveMakeLabelService;
import com.ruicar.afs.cloud.afscase.approvetask.condition.WaitTaskPoolCondition;
import com.ruicar.afs.cloud.afscase.approvetask.entity.CaseApproveRecord;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfo;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfoTemp;
import com.ruicar.afs.cloud.afscase.approvetask.service.CaseApproveRecordService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoTempService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkTaskPoolService;
import com.ruicar.afs.cloud.afscase.approvetask.vo.*;
import com.ruicar.afs.cloud.afscase.common.utils.Const;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseBaseInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseCarInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseContractInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseBaseInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseCarInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseContractInfoService;
import com.ruicar.afs.cloud.afscase.loanapprove.service.LoanWorkflowService;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.entity.CaseConfParam;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.service.CaseConfParamService;
import com.ruicar.afs.cloud.afscase.processor.service.LoanApproveWorkflowService;
import com.ruicar.afs.cloud.afscase.processor.util.WorkflowTypeUtil;
import com.ruicar.afs.cloud.afscase.processor.vo.LoanBusinessDataVO;
import com.ruicar.afs.cloud.afscase.processor.vo.LoanWorkflowDataVO;
import com.ruicar.afs.cloud.afscase.processor.vo.NormalReformistVO;
import com.ruicar.afs.cloud.common.core.constant.CommonConstants;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.security.service.AfsUser;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.core.util.IResponse;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.common.rules.RuleHelper;
import com.ruicar.afs.cloud.common.rules.constants.RuleRunEnum;
import com.ruicar.afs.cloud.common.rules.dto.RuleRunResult;
import com.ruicar.afs.cloud.seats.condition.SysUserDto;
import com.ruicar.afs.cloud.seats.entity.RegularValue;
import com.ruicar.afs.cloud.seats.entity.UserCollocation;
import com.ruicar.afs.cloud.seats.feign.UserDetailsInfoFeign;
import com.ruicar.afs.cloud.seats.service.RegularValueService;
import com.ruicar.afs.cloud.seats.service.UserCollocationService;
import com.ruicar.afs.cloud.seats.util.PostStatus;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.request.FLowGiveUpRequest;
import com.ruicar.afs.cloud.workflow.api.vo.FlowStatusVO;
import com.ruicar.afs.cloud.workflow.feign.WorkFlowServiceFeign;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @description 待分配任务池
 * @Author jiaqi.guo
 * @Date 2020/05/21 13:36
 */
@Slf4j
@RestController
@RequestMapping("/taskPool")
@Api("任务池")
@AllArgsConstructor
public class TaskPoolController {
    private final WorkTaskPoolService workTaskPoolService;

    private final CaseCarInfoService caseCarInfoService;
    private  final CaseBaseInfoService caseBaseInfoService;
    private final ApproveMakeLabelService approveMakeLabelService;
    private final CaseApproveRecordService caseApproveRecordService;
    private final RegularValueService valueService;
    private final LoanApproveWorkflowService loanApproveWorkflowService;
    private final WorkProcessScheduleInfoTempService workProcessScheduleInfoTempService;
    private final CaseContractInfoService caseContractInfoService;
    private final CaseConfParamService caseConfParamService;
    private final UserCollocationService userCollocationService;
    private final UserDetailsInfoFeign userDetailsInfoFeign;
    private final WorkProcessScheduleInfoService workProcessScheduleInfoService;

    private final WorkFlowServiceFeign workFlowServiceFeign;
    private final LoanWorkflowService loanWorkflowService;


    @GetMapping("/waitTasks")
    @ApiOperation("获取待分配任务")
    public IResponse<IPage<WaitTaskVO>> getAllWaitTask(@ModelAttribute WaitTaskPoolCondition condition) {
        //流程类型条件
        List processList = new ArrayList();
        processList.add(ProcessTypeEnum.CHANGE_ASSETS.getCode());
        processList.add(ProcessTypeEnum.FORMAL_REVIEW.getCode());
        processList.add(ProcessTypeEnum.GENERA_APPROVE.getCode());
        processList.add(ProcessTypeEnum.INVENTORIES_ARE.getCode());
        processList.add(ProcessTypeEnum.RECONSIDER_APPLY.getCode());
        processList.add(ProcessTypeEnum.SECONDARY_FRAUD.getCode());
        condition.setProcessTypeList(processList);
        //获取标签Id
        String str = condition.getTag();
        List labelIdList = new ArrayList();
        if (StringUtils.isNotEmpty(str)) {
            String[] labelId = str.split(",");
            for (int i = 0; i < labelId.length; i++) {
                labelIdList.add(labelId[i]);
            }
        }
        if (labelIdList != null && labelIdList.size() > 0) {
            condition.setLabelList(labelIdList);
        }
        // add by Peng_Jinbo 待分配与分配中
        ArrayList<String> businessStatusList = new ArrayList<>();
        businessStatusList.add(AfsEnumUtil.key(BusinessStateInEnum.ALLOCATION));  // 待分配
        businessStatusList.add(AfsEnumUtil.key(BusinessStateInEnum.TASK_ASSIGN)); // 分配失败
        businessStatusList.add(AfsEnumUtil.key(BusinessStateInEnum.TASK_ASSIGNING)); // 处于分配中
        //业务状态待分配
        condition.setBusinessStateInList(businessStatusList);
        IPage<WaitTaskVO> pageResult = workTaskPoolService.getAllWaitTaskList(
                new Page(condition.getPageNumber(), condition.getPageSize()),
                condition);

        pageResult.getRecords().forEach(waitTaskVO -> {
            /**案件基础信息*/
            CaseBaseInfo caseBaseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>query().lambda()
                    .eq(CaseBaseInfo::getApplyNo, waitTaskVO.getApplyNo()));
            /**车辆信息*/
            CaseCarInfo caseCarInfo = caseCarInfoService.getOne(Wrappers.<CaseCarInfo>query().lambda()
                    .eq(CaseCarInfo::getApplyNo, waitTaskVO.getApplyNo()));

            if (ObjectUtils.isNotEmpty(caseBaseInfo)) {
                // 当前时间，毫秒
                Long nowMilliSeconds = System.currentTimeMillis();
                // 提交时间，毫秒
                Long submitDateMilliSeconds = waitTaskVO.getPassFirstDate().getTime();
                int seconds = Convert.toInt((nowMilliSeconds - submitDateMilliSeconds) / 1000, 0);
                String hour = StringUtils.leftPad(seconds / 3600 + "", 2, '0');
                String minute = StringUtils.leftPad((seconds % 3600) / 60 + "", 2, '0');
                String second = StringUtils.leftPad((seconds % 3600) % 60 + "", 2, '0');
                // 原始读秒
                waitTaskVO.setOriginalSeconds(seconds);
                waitTaskVO.setDownPayScale(
                        Convert.toBigDecimal(waitTaskVO.getDownPayScale(), BigDecimal.ZERO).setScale(2) + "%");
                // 计时时间，页面初始化时显示
                waitTaskVO.setWaitTime(hour + " : " + minute + " : " + second);
            }
            if (Objects.nonNull(caseCarInfo)) {
                waitTaskVO.setCarName(caseCarInfo.getModelName());
            }
            /**  标签信息 **/
            List<ApproveMakeLabel> labelList = approveMakeLabelService.list(Wrappers.<ApproveMakeLabel>query().lambda()
                    .eq(ApproveMakeLabel::getApplyNo, waitTaskVO.getApplyNo()));
            waitTaskVO.setLabelList(labelList);
        });
        return IResponse.success(pageResult);
    }

    @PostMapping("/modifyLock")
    @ApiOperation("更改案件锁定状态")
    @Transactional(rollbackFor = Exception.class)
    public IResponse modifyLock(@RequestParam("data") String jsonDataArrStr,
                                @RequestParam("lockRemark") String lockRemark,
                                @RequestParam("status") String status) {
        // update by gjq 20200610
        String[] str = jsonDataArrStr.split(",");
        List applyNoLsit = new ArrayList();
        for (int i = 0; i < str.length; i++) {
            applyNoLsit.add(str[i]);
        }
        // 保存锁定、解除锁定操作备注信息
        AfsUser user = SecurityUtils.getUser();
        for (int i = 0; i < applyNoLsit.size(); i++) {
            String islock = LockEnum.LOCK.getValue();
            if (LockEnum.UN_LOCK.getName().equals(status)) {
                islock = LockEnum.UN_LOCK.getValue();
            }
            CaseApproveRecord lockOprRecord = new CaseApproveRecord();
            lockOprRecord.setApplyNo(applyNoLsit.get(i).toString());
            lockOprRecord.setApproveSuggest(status);
            lockOprRecord.setApproveSuggestName(islock);
            lockOprRecord.setApproveRemark(lockRemark);
            lockOprRecord.setDisposeStaff(user.getUserRealName());
            lockOprRecord.setApproveType(status);
            lockOprRecord.setApproveEndTime(new Date());
            caseApproveRecordService.save(lockOprRecord);
        }
        ;
        return IResponse.success(workTaskPoolService.modifyLock(applyNoLsit, status));
    }

    @PostMapping("/modifyStick")
    @ApiModelProperty("更改案件置顶状态")
    @Transactional(rollbackFor = Exception.class)
    public IResponse modifyStick(@RequestParam("data") String jsonDataArrStr,
                                 @RequestParam("status") String status) {
        // update by gjq 20200610
        String[] str = jsonDataArrStr.split(",");
        List applyNoList = new ArrayList();
        for (int i = 0; i < str.length; i++) {
            applyNoList.add(str[i]);
        }
        return IResponse.success(workTaskPoolService.modifyStick(applyNoList, status));
    }

    /**
     * @Description 查询当前操作组所有人员
     * @Author rj.zhang
     * @Date 2020/7/30
     */
    @GetMapping("/listTaskHandler")
/*    @PreAuthorize("@pms.hasPermission('approve_handler_change')")*/
    public IResponse getNodeHandler() {
        CaseConfParam param = caseConfParamService.getOne(
                Wrappers.<CaseConfParam>lambdaQuery()
                        .eq(CaseConfParam::getParamType, Const.PARAMS_TASK_CASE_DEPARTMENT)
        );
        if (Objects.isNull(param)) {
            return IResponse.fail("任务改派部门参数不存在，请先维护当前参数");
        }
        IResponse<List<SysUserDto>> response = userDetailsInfoFeign.getUsersByDepartmentId(param.getParamValue());
        if (CommonConstants.SUCCESS.equals(response.getCode())) {
            List<UserCollocation> userCollocationList = userCollocationService.list();
            Map<String, String> userStatusMap = new HashMap<>();
            if (CollectionUtil.isNotEmpty(userCollocationList)) {
                for (UserCollocation userCollocation : userCollocationList) {
                    userStatusMap.put(userCollocation.getLoginName(), userCollocation.getPostStatus());
                }
            }
            List<SysUserDto> userDtoList = response.getData();
            List<TaskHandlerVO> taskHandlerVOList = new ArrayList<>(userDtoList.size());
            for (SysUserDto sysUserDto : userDtoList) {
                String status = userStatusMap.get(sysUserDto.getUsername());
                taskHandlerVOList.add(TaskHandlerVO.builder()
                        .staffName(sysUserDto.getUsername())
                        .staffRealName(sysUserDto.getUserRealName())
                        .postStatus(Objects.isNull(status) ? PostStatus.NO.getCode() : status).build());
            }
            List result = Lists.partition(taskHandlerVOList, 10);
            TaskHandlerPageVO pageVO = TaskHandlerPageVO.builder()
                    .dataTotal(taskHandlerVOList.size())
                    .pageList(result)
                    .allDataList(taskHandlerVOList).build();
            return IResponse.success(pageVO);
        } else {
            return IResponse.fail(response.getMsg());
        }
    }

    /**
     * @Description 指定处理人流程发起
     * @Author rj.zhang
     * @Date 2020/7/30
     */
    @PostMapping("/appointFlow")
    public IResponse appointFlow(@RequestBody WorkflowAppointVO workflowAppointVO) {
        CaseContractInfo caseContractInfo = caseContractInfoService.getOne( Wrappers.<CaseContractInfo>lambdaQuery().eq(CaseContractInfo::getContractNo, workflowAppointVO.getContractNo()));
            RuleRunResult result = RuleHelper.runRule(workTaskPoolService.getRuleJSONObject(caseContractInfo), "loanProcedure", false, RuleRunEnum.SERIAL);
            if (result.getHit()) {
                List listNo = result.getResults().stream().map(s -> {
                    return s.getRuleNo();
                }).collect(Collectors.toList());

                if (listNo.isEmpty())
                    return IResponse.fail("操作失败");
                List<RegularValue> valueList = valueService.listByIds(listNo);
                if (valueList == null || valueList.isEmpty())
                    return IResponse.fail("操作失败");
                String[] value = valueList.stream().map(s -> {
                    String[] str = s.getValue().split("#");
                    return str;
                }).max(Comparator.comparing(s -> s[1])).get();

                log.info("流程匹配命中结果[{}],流程编号为[{}]", result.getHit(), value[1]);
                //流程分支条件参数
                LoanBusinessDataVO loanBusinessDataVO = LoanBusinessDataVO.builder()
                        .assigned(WhetherEnum.YES.getCode())
                        .build();
                /**如果分配人员失败，需废弃原流程再重新分配*/
                if (caseContractInfo.getApplyStatus().equals(ApplyStatusEnum.WAIT_ASSIGN.getState())){
                    WorkProcessScheduleInfo info= workProcessScheduleInfoService.getOne(Wrappers.<WorkProcessScheduleInfo>lambdaQuery()
                            .eq(WorkProcessScheduleInfo::getContractNo,caseContractInfo.getContractNo()).eq(WorkProcessScheduleInfo::getAfsFlowKey,value[1]),false);
                    if(ObjectUtils.isNotEmpty(info)){
                        log.info("废弃合同{}流程{}实例ID{}开始===",caseContractInfo.getContractNo(),value[1],info.getStageId());
                        FLowGiveUpRequest fLowGiveUpRequest = new FLowGiveUpRequest();
                        fLowGiveUpRequest.setReason("指定处理人废弃流程");
                        fLowGiveUpRequest.setFlowInstanceId(info.getStageId());
                        loanApproveWorkflowService.flowGiveUp(fLowGiveUpRequest);
                        workProcessScheduleInfoService.removeById(info);
                        caseApproveRecordService.remove(Wrappers.<CaseApproveRecord>lambdaQuery()
                                .eq(CaseApproveRecord::getContractNo,caseContractInfo.getContractNo())
                                .eq(CaseApproveRecord::getStageId,info.getId().toString()));
                        log.info("废弃合同{}流程{}实例ID{}结束===",caseContractInfo.getContractNo(),value[1],info.getStageId());
                    }else {
                        log.info("未找到合同{}流程{}",caseContractInfo.getContractNo(),value[1]);
                    }
                }
                //保存发起指定处理的操作人员日志
                CaseApproveRecord record = new CaseApproveRecord();
                record.setContractNo(caseContractInfo.getContractNo());
                record.setUseScene(UseSceneEnum.GENERAL_LOAN.getValue());
                record.setDisposeStaff(SecurityUtils.getUser().getUserRealName());
                record.setDisposeNodeName("指定初审");
                record.setApproveSuggestName("指定处理人");
                record.setApproveStartTime(new Date());
                record.setApproveEndTime(new Date());
                record.setApproveRemark("发起指定处理人流程");
                caseApproveRecordService.save(record);
                //流程发起
                loanApproveWorkflowService.start(LoanWorkflowDataVO.builder()
                        .loanBusinessDataVO(loanBusinessDataVO)
                        .workProcessScheduleInfoTemp(createLocalWorkProcessor(caseContractInfo, workflowAppointVO, value[1]))
                        .build());
                return IResponse.success("操作成功");
            }else {
            return IResponse.fail("操作失败");
        }
    }

    /**
     * @param
     * @description 创建流程实例
     * @author rj.zhang
     * @date 2020/7/30
     */
    @Transactional
    public WorkProcessScheduleInfoTemp createLocalWorkProcessor(CaseContractInfo caseContractInfo,WorkflowAppointVO workflowAppointVO, String afsFlowKey) {
        // 保存工作流实例
        WorkProcessScheduleInfoTemp info = new WorkProcessScheduleInfoTemp();
        info.setAfsFlowKey(afsFlowKey);
        info.setApplyNo(caseContractInfo.getApplyNo());
        info.setContractNo(caseContractInfo.getContractNo());
        info.setAppointHandler(workflowAppointVO.getAppointStaff());
        info.setProcessName(WorkflowTypeUtil.getApproveTypeName(afsFlowKey));
        info.setStartTime(new Date());
        workProcessScheduleInfoTempService.save(info);
        return info;
    }

    /**
     * @Description 任务操作人变更
     * @Author Peng_Jinbo
     * @Date 2020/7/7 20:41
     */
    @PostMapping("/taskHandler")
    public IResponse taskHandler(@RequestBody TaskHandlerChangeVO taskHandlerChangeVO) {
        return IResponse.success(loanApproveWorkflowService.reformist(NormalReformistVO.builder()
                .stageId(taskHandlerChangeVO.getStageId())
                .reformistUserName(taskHandlerChangeVO.getUserName())
                .reformistUserRealName(taskHandlerChangeVO.getUserRealName())
                .oriUserName(taskHandlerChangeVO.getOriUserName()).build()).getMessage());
    }

    @GetMapping("/getFlowInstanceByApplyNo/{applyNo}")
    public IResponse<List<FlowStatusVO>> queryWorkFlowInstanceByApplyNo(@PathVariable String applyNo){
        List<String> flowInstanceIds = workProcessScheduleInfoService.queryFlowInstanceIdsByApplyNo(applyNo);
        if (CollectionUtil.isEmpty(flowInstanceIds)){
            return IResponse.success(new ArrayList<>());
        }else {
            try{
                return workFlowServiceFeign.queryFlowInstanceStatus(CollectionUtil.join(flowInstanceIds,","));
            }catch (Exception e){
                return IResponse.success(new ArrayList<>());
            }
        }
    }
}
